#include "./app_dac.h"
#include "./app_flash.h"
#include "./app_adc.h"
#include "./app_can.h"
#include "./app_led.h"
#include "./app_device.h"
struct dac_dev_t *output_dac;
uint32_t dacSetVal=0;
uint16_t voutSetVal=0,ioutSetVal=0;
extern uint16_t  canVoutSetVal;
uint32_t dacTimeCount=0;
extern uint8_t aver_flag ;
extern uint16_t ioutMaxVal,voutMaxVal;

uint16_t lastDac = 0;
uint32_t dacSetSeed = 0;
uint32_t avsetSpeed = 0;
extern float VolVout        ;
extern float VolIout        ;
uint16_t limitToDac;//限定电压对应的dac值
float IoutProtectVal;//电流保护值

/*
    模块电流的优先级更高，
    也就是说模块的电流达到设定值时，
    就需要降低模块的输出电压（降低DAC输出电压）
    直到电流值恒定在这个设定值，
    没有达到模块电流的设定值，
    就按照控制单元设定的电压值调节
*/
extern uint16_t voutMaxDefault;

void app_dac_init(void)
{
		uint16_t load = 0;
    dac_init(&output_dac);
    app_load_dac_fator(output_dac->factor);
	

	load = output_dac->get_vol_val(output_dac,app_load_vout_max_default());
				output_dac->change_setting_val(output_dac, load);


    output_dac->set_out(output_dac);
//    voutMaxVal=app_load_vout_max();
//    ioutMaxVal=app_load_iout_max();

} 
static float avr_tmp = 0;
extern uint16_t canAvrIoutval;
static uint16_t avrDacMax,avrDacMin;
static float avrIoutUpper;//均流上限值
static float avrIoutLower;//均流下限值
uint16_t avrDac = 0;
void calculate_avr_iout(void)
{
	


		
	if(canAvrIoutval>0)
	{
		avr_tmp = canAvrIoutval;
		avr_tmp = avr_tmp/10;
		avrIoutLower = avr_tmp*0.90;
		avrIoutUpper = avr_tmp*1.10;
	}
	else 
	{
		return;
	}
	//1.均流值不在再可调范围
	if((avr_tmp<avrIoutLower)||(avr_tmp>avrIoutUpper))
	{
			return;
	}
	avrDac = output_dac->get_setting_val(output_dac);
	//当前电流值小于均流值
	if(VolIout<avr_tmp)
	{
		avrDac = avrDac + 1;
		
	}
	else if(VolIout>avr_tmp)
	{
		avrDac = avrDac - 1;
		
	}
	//dac值是否再可调范围
	if((avrDac>avrDacMax)||(avrDac<avrDacMin))
	{
		return ;
	}
	output_dac->change_setting_val(output_dac, avrDac);		
	output_dac->set_out(output_dac);//调整dac
}
/**
 * @brief 根据电流 控制dac
 * 
 * @param iout 当前电流值
 * @param vout_th vout阈值
 * @param up_val 上限值
 * @param low_val 下限值
*/
uint16_t calDac;
static uint8_t calculate_iout_control_dac(float iout,uint16_t dac_th,float up_val,float low_val)
{
	uint16_t tmp = 0;
	if(iout==0)return 0;
	if(up_val==0)return 0;
	if(low_val==0)return 0;

	//限流值*0.95≤输出电流≤限流值*1.05
	if((iout>=low_val)&&(iout<=up_val))
	{
		//dac 不做处理
	}
	else if(iout < low_val)//输出电流＜限流值*0.95 加 1
	{
		calDac = output_dac->get_setting_val(output_dac);
		//判断DAC与基准值的关系 
		if(calDac>= dac_th)//超出dac范围
		{
		//	tmp = dac_th;// ricky
			
			output_dac->change_setting_val(output_dac, calDac);		
		}
		else
		{
			
			//dac值是否再可调范围
			if((calDac>avrDacMax)||(calDac<avrDacMin))
			{
				calDac = calDac + 1;
			}
			else {
				calDac = calDac;
				
			}
			output_dac->change_setting_val(output_dac, calDac);
		}
		
	}
	else if(iout > up_val) //输出电流＞限流值*1.05 dac 减小
	{
		//过去当前输出设定值，减 1
		
        calDac = output_dac->get_setting_val(output_dac);
        calDac = calDac - 1;
        output_dac->change_setting_val(output_dac, calDac);
	}
	else 
	{

	}
	output_dac->set_out(output_dac);//调整dac
}

extern uint16_t voutMaxDefault;
static float limitVoutMax;//最大限压值
static uint16_t limitIoutMax;//最大限流值
static float limitIoutUpper;//限流上限值
static float limitIoutLower;//限流下限值
/**
 * @brief no dac 没有通信情况下，dac 处理
*/
void app_dac_no_communication(void)
{
	float iout_tmp;
	uint16_t tmp = 0;
	if(canVoutSetVal>10)//can有通信
    { 	
				limitVoutMax = canVoutSetVal/10;	
				limitToDac = output_dac->get_vol_val(output_dac,canVoutSetVal);
	}
	else
	{
		limitVoutMax = voutMaxDefault/10;
		limitToDac = output_dac->get_vol_val(output_dac,voutMaxDefault);
	}
	//limitVoutMax = voutMaxDefault/10;
	//限流处理
	iout_tmp = ioutMaxVal;
	iout_tmp =iout_tmp/10;//模块过流 
	//erf_val = iout_tmp*0.05;
	limitIoutLower = iout_tmp*0.97;//5;
	limitIoutUpper = iout_tmp*1.0;
    
	
	
	//输出电压小于等于设置电压
	//DAC调整时 输出电压 小于基准电压
	
	if ( lastDac ==limitToDac)
			dacSetSeed = 0;
	
	if ( lastDac < limitToDac)
	{
		calculate_iout_control_dac(VolIout,limitToDac,limitIoutUpper,limitIoutLower);
	}
	else
	{

		tmp = output_dac->get_setting_val(output_dac);
		tmp = tmp - 1;
		output_dac->change_setting_val(output_dac, tmp);
		output_dac->set_out(output_dac);//调整dac
	}
	
	lastDac = output_dac->get_setting_val(output_dac);
}


void app_dac_loop_func(void)
{
	avrDacMax = limitToDac;
	avrDacMin = limitToDac*0.99;
	if( dacTimeCount>dacSetSeed)
	{

		app_dac_no_communication();
		dacTimeCount = 0;
	}
	if(avsetSpeed>20000)
	{
		avsetSpeed=0;
		calculate_avr_iout();
	}
	avsetSpeed++;
}

